{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2.3.1'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建变量\n",
    "v = tf.Variable(0.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.0"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(v + 1).numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'UnreadVariable' shape=() dtype=float32, numpy=5.0>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 改变变量值\n",
    "v.assign(5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=5.0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'UnreadVariable' shape=() dtype=float32, numpy=6.0>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 加一\n",
    "v.assign_add(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=6.0>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=float32, numpy=6.0>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 读取变量值\n",
    "v.read_value()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 自动微分运算(只能计算float类型的数据)\n",
    "w = tf.Variable([[1.0]])\n",
    "with tf.GradientTape() as t: # 上下文管理器\n",
    "    loss = w * w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[2.]], dtype=float32)>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 求解loss对w的微分/梯度\n",
    "grad = t.gradient(loss,w)\n",
    "grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 自动微分运算\n",
    "w = tf.constant(3.0)\n",
    "with tf.GradientTape() as t:\n",
    "    t.watch(w) # t跟踪w的运算\n",
    "    loss = w * w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "dloss_dw = t.gradient(loss,w)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=float32, numpy=6.0>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dloss_dw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 自动微分运算\n",
    "w = tf.constant(3.0)\n",
    "with tf.GradientTape(persistent = True) as t: # persistent = True将微分持久记录，可以多次计算微分\n",
    "    t.watch(w) # t跟踪w的运算\n",
    "    y = w * w\n",
    "    z = y * y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=float32, numpy=6.0>"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dy_dx = t.gradient(y,w)\n",
    "dy_dx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(), dtype=float32, numpy=108.0>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dz_dw = t.gradient(z, w)\n",
    "dz_dw"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "自定义训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "(train_images,train_labels) ,(test_images,test_labels) = tf.keras.datasets.mnist.load_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(60000, 28, 28)"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_images.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 改变数据类型\n",
    "train_images = tf.cast(train_images/255,tf.float32)\n",
    "test_images = tf.cast(test_images/255,tf.float32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_labels = tf.cast(train_labels,tf.int64)\n",
    "test_labels = tf.cast(test_labels,tf.int64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_images = tf.expand_dims(train_images,-1) # 扩张维度，扩张最后一列为1\n",
    "test_images = tf.expand_dims(test_images,-1) # 扩张维度，扩张最后一列为1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(60000,), dtype=int64, numpy=array([5, 0, 4, ..., 5, 6, 8], dtype=int64)>"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = tf.data.Dataset.from_tensor_slices((train_images,train_labels))\n",
    "test_dataset = tf.data.Dataset.from_tensor_slices((test_images,test_labels))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<TensorSliceDataset shapes: ((28, 28, 1, 1), ()), types: (tf.float32, tf.int64)>,\n",
       " <TensorSliceDataset shapes: ((28, 28, 1, 1), ()), types: (tf.float32, tf.int64)>)"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dataset,test_dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = dataset.shuffle(10000).batch(32) # 不设置repeat()时默认会重复一次\n",
    "test_dataset = test_dataset.batch(32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<BatchDataset shapes: ((None, 28, 28, 1, 1), (None,)), types: (tf.float32, tf.int64)>,\n",
       " <BatchDataset shapes: ((None, 28, 28, 1, 1), (None,)), types: (tf.float32, tf.int64)>)"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dataset,test_dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = tf.keras.Sequential([\n",
    "    tf.keras.layers.Conv2D(16,(3,3),activation='relu',input_shape=(None,None,1)), # (None,None,1)表示图片大小任意\n",
    "    tf.keras.layers.Conv2D(32,(3,3),activation='relu'),\n",
    "    tf.keras.layers.GlobalMaxPooling2D(),\n",
    "    tf.keras.layers.Dense(10)\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 自定义循环\n",
    "optimizer = tf.keras.optimizers.Adam()\n",
    "loss_func = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) # 未激活，from_logits=True\n",
    "features, labels = next (iter(dataset)) # 取出第一个批次的数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "predictions  = model(features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "TensorShape([32, 10])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "predictions.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(32,), dtype=int64, numpy=\n",
       "array([6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,\n",
       "       6, 6, 6, 6, 6, 6, 6, 6, 6, 6], dtype=int64)>"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.argmax(predictions,axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<tf.Tensor: shape=(32,), dtype=int64, numpy=\n",
       "array([2, 7, 3, 4, 5, 4, 0, 7, 4, 0, 9, 7, 2, 6, 9, 4, 9, 5, 2, 8, 1, 1,\n",
       "       4, 5, 3, 9, 0, 2, 9, 4, 9, 5], dtype=int64)>"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 初始化计算对象\n",
    "train_loss = tf.keras.metrics.Mean('train_loss')\n",
    "train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('train_accuracy') \n",
    "test_loss = tf.keras.metrics.Mean('test_loss')\n",
    "test_accuracy = tf.keras.metrics.SparseCategoricalAccuracy('test_accuracy') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义损失函数，loss返回交叉熵损失\n",
    "def loss(model, x, y):\n",
    "    y_ = model(x)\n",
    "    return loss_func(y,y_) # y_为预测值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_step(model,images,labels):\n",
    "    with tf.GradientTape() as t:\n",
    "        pred = model(images)\n",
    "        loss_step = loss_func(labels,pred)\n",
    "        #loss_step = loss(model,images,labels) # 每一步的损失值\n",
    "    grads = t.gradient(loss_step,model.trainable_variables) # 损失函数与可训练参数之间的梯度\n",
    "    optimizer.apply_gradients(zip(grads,model.trainable_variables)) # 优化函数应用梯度进行优化\n",
    "    # 汇总计算平均loss\n",
    "    train_loss(loss_step)\n",
    "    # 汇总计算平均acc\n",
    "    train_accuracy(labels,pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "def test_step(model,images,labels):\n",
    "        pred = model(images)\n",
    "        loss_step = loss_func(labels,pred)\n",
    "        # 汇总计算平均loss\n",
    "        test_loss(loss_step)\n",
    "        # 汇总计算平均acc\n",
    "        test_accuracy(labels,pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train():\n",
    "    for epoch in range(10):\n",
    "        for (batch,(images,labels)) in enumerate(dataset):\n",
    "            train_step(model,images,labels)\n",
    "        print('Epoch{}  loss is {}, accuracy is {}'.format(epoch,train_loss.result(),train_accuracy.result()))\n",
    "        for (batch,(images,labels)) in enumerate(test_dataset):\n",
    "            test_step(model,images,labels)\n",
    "        print('Epoch{}  test_loss is {}, test_accuracy is {}'.format(epoch,test_loss.result(),test_accuracy.result()))\n",
    "        # 重置\n",
    "        train_loss.reset_states()\n",
    "        train_accuracy.reset_states()\n",
    "        test_loss.reset_states()\n",
    "        test_accuracy.reset_states()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch0  loss is 2.301481008529663, accuracy is 0.11178333312273026\n",
      "Epoch0  test_loss is 2.3004038333892822, test_accuracy is 0.11349999904632568\n",
      "Epoch1  loss is 2.256425619125366, accuracy is 0.17403332889080048\n",
      "Epoch1  test_loss is 2.1326065063476562, test_accuracy is 0.22669999301433563\n",
      "Epoch2  loss is 2.0264012813568115, accuracy is 0.2898666560649872\n",
      "Epoch2  test_loss is 1.9405102729797363, test_accuracy is 0.34360000491142273\n",
      "Epoch3  loss is 1.896636724472046, accuracy is 0.368966668844223\n",
      "Epoch3  test_loss is 1.824200987815857, test_accuracy is 0.4156999886035919\n",
      "Epoch4  loss is 1.7756662368774414, accuracy is 0.42524999380111694\n",
      "Epoch4  test_loss is 1.6926041841506958, test_accuracy is 0.43950000405311584\n",
      "Epoch5  loss is 1.635901927947998, accuracy is 0.4648166596889496\n",
      "Epoch5  test_loss is 1.560739278793335, test_accuracy is 0.4733000099658966\n",
      "Epoch6  loss is 1.501874327659607, accuracy is 0.49818333983421326\n",
      "Epoch6  test_loss is 1.4185281991958618, test_accuracy is 0.5163999795913696\n",
      "Epoch7  loss is 1.389702320098877, accuracy is 0.5253833532333374\n",
      "Epoch7  test_loss is 1.3155063390731812, test_accuracy is 0.5504999756813049\n",
      "Epoch8  loss is 1.3028371334075928, accuracy is 0.5513166785240173\n",
      "Epoch8  test_loss is 1.2352187633514404, test_accuracy is 0.5764999985694885\n",
      "Epoch9  loss is 1.2359925508499146, accuracy is 0.5677000284194946\n",
      "Epoch9  test_loss is 1.1754173040390015, test_accuracy is 0.5925999879837036\n"
     ]
    }
   ],
   "source": [
    "train()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "tf.kears.metrics汇总计算模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 计算均值\n",
    "m = tf.keras.metrics.Mean('acc')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 得到计算均值的结果\n",
    "m.result()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 重置均值计算状态：0\n",
    "m.reset_states()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = tf.keras.metrics.SparseCategoricalAccuracy('acc')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 自动选出model(features)中的最大值与labels进行比较\n",
    "a(labels,model(features))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
